from zope.interface import implements

from twisted.application import internet
from twisted.internet import protocol, defer, reactor
from twisted.mail import smtp, relaymanager
from twisted.plugin import IPlugin

from pyhsrv.interfaces import IActionPlugin
from pyhsrv import errors

import StringIO
import time


class SMTPClient(smtp.ESMTPClient):

    def getMailFrom(self):
        result = self.factory.mailFrom
        self.factory.mailFrom = None
        return result

    def getMailTo(self):
        return self.factory.mailTo

    def getMailData(self):
        return StringIO.StringIO(self.factory.mailData)

    def sentMail(self, code, resp, numOk, addresses, log):
        print 'Sent', numOk, 'messages'

class SMTPClientFactory(protocol.ClientFactory):
    
    protocol = SMTPClient
    
    def __init__(self, from_addr, to_addr, msg):
        self.mailFrom = from_addr
        self.mailTo = to_addr
        self.mailData = msg

    def buildProtocol(self, addr):
        p = self.protocol(secret=None, identity=self.mailFrom.split('@')[1])
        p.factory = self
        return p

class MailSenderAction(object):
    
    implements(IPlugin, IActionPlugin)

    def configure(self, cfg, db):
        self.from_addr = cfg.get('mail', 'sender')
        self.cfg = cfg

    def getName(self):
        return "mail"

    def doAction(self, tmstmp, node, item, value, type, group, msg):
        
        def composemsg(from_addr):
            def formatMsg(to_addrs, from_addr):
                message = "Date: " + time.ctime(tmstmp) + "\n"
                message += "From: " + from_addr + "\n"
                message += "To: " + ','.join(to_addrs) + "\n"
                message += "Subject: [Alert] " + node + "\n"
                message += "Alert: on " + node + " the " + item + "  " + type
                message += " happened: " +  value + "\n"
                message += msg
                return message
            d = self.db.getMailAddrsForGroup(group, session = True)
            d.addErrback(errors.catchError)
            d.addCallback(formatMsg, from_addr)
            return d
      
        def getMailExchange(host):
            def cbMX(mxRecord):
                return str(mxRecord.exchange)
            return relaymanager.MXCalculator().getMX(host).addCallback(cbMX)

        def getMailFactory(msg, exchange):
            smtpClientFactory = SMTPClientFactory(self.from_addr, to_addr, msg)
            reactor.connectTCP('localhost', self.cfg.getint('mail', 'port'), smtpClientFactory)
            
        def cbMailExchange(exchange):
            composemsg(self.from_addr).addCallback(getMailFactory, exchange)

        getMailExchange(self.cfg.get('mail', 'server')).addCallback(cbMailExchange)

ms = MailSenderAction()